﻿// Solution: TESZT
// Project: WpfApplication2
// FileName: SQLScripLoader.cs
// Created: 2015.07.14 16:00
// Last format: 2015.07.14 20:14
// UserName: kp

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Common.IO
{
  public class SqlScripLoader
  {
    #region ... constructors...

    public SqlScripLoader()
    {
      fProcessTable.Add( '-', MinusProc );
      fProcessTable.Add( '/', SlashProc );
      fProcessTable.Add( '\'', AsciiStringProc );
      fProcessTable.Add( '"', QuoteStringProc );
    }

    #endregion

    #region ... properties indexers ...

    public IEnumerable<string> Commands
    {
      get { return fCommandList.ToArray(); }
    }

    #endregion

    #region ...public methods...

    public void Load( string scriptName )
    {
      fTerm = ";";
      fCommandList.Clear();
      fBuffer = new StringBuilder();

      using ( fReader = ScriptReader.CreateFromFile( scriptName ) )
      {
        while ( NextChar() )
        {
          Action action = null;
          if ( fProcessTable.TryGetValue( (char)fReader.Current, out action ) )
          {
            action();
            continue;
          }

          if ( fReader.Current != fTerm[0] )
            continue;

          if ( fTerm.Length > 1 )
          {
            if ( fReader.Next != fTerm[1] )
              continue;

            NextChar();
          }

          var buffer = fBuffer.ToString().Trim().Split( '\r' ).Last().Trim();
          if ( buffer.StartsWith( "set term", StringComparison.InvariantCultureIgnoreCase ) )
            fTerm = buffer.Remove( 0, 8 ).Trim().Replace( fTerm, string.Empty );
          else
            fCommandList.Add( fBuffer.ToString() );

          fBuffer.Clear();
        }
      }
    }

    #endregion

    #region ...private methods...

    private void AsciiStringProc()
    {
      var ref_string = string.Empty;

      if ( !fReader.ReadAtSeparator( '\'', ref ref_string ) )
        return;

      fBuffer.Append( ref_string );
    }

    private void MinusProc()
    {
      NextChar();
      if ( fReader.Current != '-' )
        return;

      var ref_string = string.Empty;
      fReader.ReadAtEol( ref ref_string );

      if ( !string.IsNullOrEmpty( ref_string ) )
        fBuffer.Append( ref_string );
    }

    private bool NextChar()
    {
      var result = fReader.NextChar();
      if ( result )
        fBuffer.Append( (char)fReader.Current );

      return result;
    }

    private void QuoteStringProc()
    {
      var ref_string = string.Empty;

      if ( !fReader.ReadAtSeparator( '"', ref ref_string ) )
        return;

      fBuffer.Append( ref_string );
    }

    private void SlashProc()
    {
      var req_command = fBuffer.ToString().Trim().Length == 1;

      NextChar();
      if ( fReader.Current != '*' )
        return;

      var ref_string = string.Empty;

      if ( !fReader.ReadAtSeparator( "*/", ref ref_string ) )
        return;

      fBuffer.Append( ref_string );
      if ( !req_command )
        return;

      fCommandList.Add( fBuffer.ToString() );
      fBuffer.Clear();
    }

    #endregion

    #region ... fields ...

    private readonly List<string> fCommandList = new List<string>();
    private readonly SortedList<char, Action> fProcessTable = new SortedList<char, Action>();

    private StringBuilder fBuffer;
    private ScriptReader fReader;
    private string fTerm = ";";

    #endregion
  }
}
